#include "utils.h"
#include "peripherals/mini_uart.h"
#include "peripherals/gpio.h"


#define BUFFER_SIZE 32
static char buffer[BUFFER_SIZE];
static unsigned int wr_buffer_index = 0;
static unsigned int rd_buffer_index = 0;

void uart_send ( char c )
{
	while(1) {
		if(get32(AUX_MU_LSR_REG)&0x20) 
			break;
	}
	put32(AUX_MU_IO_REG,c);
}

char uart_recv ( void )
{
	while(1) {
		if(get32(AUX_MU_LSR_REG)&0x01) 
			break;
	}
	return(get32(AUX_MU_IO_REG)&0xFF);
}

void uart_send_string(char* str)
{
	for (int i = 0; str[i] != '\0'; i ++) {
		uart_send((char)str[i]);
	}
}

void uart_init ( void )
{
	unsigned int selector;

	selector = get32(GPFSEL1);
	selector &= ~(7<<12);                   // clean gpio14
	selector |= 2<<12;                      // set alt5 for gpio14
	selector &= ~(7<<15);                   // clean gpio15
	selector |= 2<<15;                      // set alt5 for gpio15
	put32(GPFSEL1,selector);

	put32(GPPUD,0);
	delay(150);
	put32(GPPUDCLK0,(1<<14)|(1<<15));
	delay(150);
	put32(GPPUDCLK0,0);

	put32(AUX_ENABLES,1);                   //Enable mini uart (this also enables access to it registers)
	put32(AUX_MU_CNTL_REG,0);               //Disable auto flow control and disable receiver and transmitter (for now)
	put32(AUX_MU_IER_REG,3);                //Enable receive interrupt and transmit interrupts
	put32(AUX_MU_LCR_REG,3);                //Enable 8 bit mode
	put32(AUX_MU_MCR_REG,0);                //Set RTS line to be always high
	put32(AUX_MU_BAUD_REG,270);             //Set baud rate to 115200

	put32(AUX_MU_CNTL_REG,3);               //Finally, enable transmitter and receiver
}

void handle_uart_irq()
{
	unsigned int id = get32(AUX_MU_IIR_REG);
	if((id & 0x06) == 0x04)
	{
		while(get32(AUX_MU_LSR_REG)&0x01)
		{
			buffer[wr_buffer_index++] = get32(AUX_MU_IO_REG)&0xFF;
			if(wr_buffer_index == BUFFER_SIZE)
				wr_buffer_index = 0;
		}
	}
	if((id & 0x06) == 0x02)
	{
		while(get32(AUX_MU_LSR_REG)&0x20) 
		{
			if(rd_buffer_index == wr_buffer_index)
			  break;
			char c = buffer[rd_buffer_index++];
			put32(AUX_MU_IO_REG,c);
			if(rd_buffer_index == BUFFER_SIZE)
				rd_buffer_index = 0;
		}
	}
}

// This function is required by printf function
void putc ( void* p, char c)
{
	uart_send(c);
}
